package cn.js189.uqc.redis;

import cn.hutool.core.text.CharSequenceUtil;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import redis.clients.jedis.*;

import javax.annotation.PostConstruct;
import java.util.*;

/**
 * @program: xxb
 * @description:
 * @author: jzd
 * @create: 2024/2/28 14:45
 **/
@Component
public class RedisOperation {
    private static final Logger logger = LoggerFactory.getLogger(RedisOperation.class);

    @Value("${redis.clusterA.nodes}")
    private String clusterA;

    @Value("${redis.clusterB.nodes}")
    private String clusterB;

    @Value("${redis.clusterA.password}")
    private String passwordA;

    @Value("${redis.clusterB.password}")
    private String passwordB;

    @Value("${redis.pool.maxIdle}")
    private int maxIdle;

    @Value("${redis.pool.maxWait}")
    private int maxWait;

    @Value("${redis.pool.maxActive}")
    private int maxActive;

    @Value("${redis.connectionTimeOut}")
    private int connectionTimeOut;

    @Value("${redis.soTimeout}")
    private int soTimeout;

    @Value("${redis.maxAttempts}")
    private int maxAttempts;

    //仪征redis集群
    private JedisCluster jedisClusterA;

    //吉山redis集群
    private JedisCluster jedisClusterB;

    @PostConstruct
    private void initCluster(){
        //连接池配置
        GenericObjectPoolConfig poolConfig = new JedisPoolConfig(); //线程池配置
        poolConfig.setMaxTotal(maxActive); // 最大连接数（空闲+使用中）
        poolConfig.setMaxIdle(maxIdle); //最大空闲连接数
        poolConfig.setMaxWaitMillis(maxWait);

        try {
            logger.info("----初始化仪征redisCluster开始----");
            Set<HostAndPort> yzHostAndPortList = new HashSet<>();
            List<String> yzServerNodes = CharSequenceUtil.split(clusterA,",");
            for (String ipPort : yzServerNodes) {
                String[] ipAndPort = ipPort.split(":");
                yzHostAndPortList.add(new HostAndPort(ipAndPort[0].trim(), Integer.parseInt(ipAndPort[1])));
            }
            jedisClusterA = new JedisCluster(yzHostAndPortList,connectionTimeOut,soTimeout,maxAttempts,passwordA,poolConfig);
            logger.info("----初始化仪征redisCluster成功----");
        } catch (Exception e) {
            logger.error("初始化仪征redisCluster失败,"+e.getMessage(),e);
        }

        try {
            logger.info("----初始化吉山redisCluster开始----");
            Set<HostAndPort> jsHostAndPortList = new HashSet<>();
            List<String> jsServerNodes = CharSequenceUtil.split(clusterB,",");
            for (String ipPort : jsServerNodes) {
                String[] ipAndPort = ipPort.split(":");
                jsHostAndPortList.add(new HostAndPort(ipAndPort[0].trim(), Integer.parseInt(ipAndPort[1])));
            }
            jedisClusterA = new JedisCluster(jsHostAndPortList,connectionTimeOut,soTimeout,maxAttempts,passwordA,poolConfig);
            logger.info("----初始化吉山redisCluster成功----");
        } catch (Exception e) {
            logger.error("初始化吉山redisCluster失败,"+e.getMessage(),e);
        }
    }

    /**
     * Description: 增加k,v数据
     *
     * @param key   key
     * @param value value<br>
     * @author zhangai<br>
     * @taskId <br>
     */
    public String setForString(String key, String value) {
        String result = "";
        try {
            result = jedisClusterA.set(key, value);
        } catch (Exception e) {
            logger.error("redis主节点写失败，" + e.getMessage(), e);
        }
        try {
            result = jedisClusterB.set(key, value);
        } catch (Exception e) {
            logger.error("redis从节点写失败，" + e.getMessage(), e);
        }
        return result;
    }

    /**
     * Description:获取指定key的value数据
     *
     * @param key key
     * @return <br>
     * @author zhangai<br>
     * @taskId <br>
     */
    public String getForString(String key) {
        String result = "";
        try {
            result = jedisClusterA.get(key);
        } catch (Exception e) {
            logger.error("redis主节点失败，" + e.getMessage(), e);
            try {
                result = jedisClusterB.get(key);
            } catch (Exception ex) {
                logger.error("redis从节点失败，" + ex.getMessage(), ex);
            }
        }
        return result;
    }

    /**
     * 查询redis hash的长度
     * Description: <br>
     *
     * @param key
     * @return String<br>
     * @author yangyang<br>
     * 2020年6月11日
     */
    public String getForHashLenth(String key) {
        String result = "";
        try {
            result = jedisClusterA.hlen(key).toString();
        } catch (Exception e) {
            logger.error("redis主节点失败，" + e.getMessage(), e);
        }
        if (StringUtils.isBlank(result)) {
            try {
                result = jedisClusterB.hlen(key).toString();
            } catch (Exception e) {
                logger.error("redis从节点失败，" + e.getMessage(), e);
            }
        }
        return result;

    }

    /**
     * Description: <br>
     *
     * @param key   key
     * @param field key对应的域
     * @param value value <br>
     * @author zhangai<br>
     * @taskId <br>
     */
    public void setForHash(String key, String field, String value) {
        try {
            jedisClusterA.hset(key, field, value);
        } catch (Exception e) {
            logger.error("redis主节点失败，" + e.getMessage(), e);
        }
        try {
            jedisClusterB.hset(key, field, value);
        } catch (Exception e) {
            logger.error("redis从节点失败，" + e.getMessage(), e);
        }
    }

    /**
     * Description: <br>
     *
     * @param key   key
     * @param field key对应的域
     * @return <br>
     * @author zhangai<br>
     * @taskId <br>
     */

    public String getForHash(String key, String field) {
        String result = "";
        try {
            result = jedisClusterA.hget(key, field);
        } catch (Exception e) {
            logger.error("redis主节点失败，" + e.getMessage(), e);
            try {
                result = jedisClusterB.hget(key, field);
            } catch (Exception ex) {
                logger.error("redis从节点失败，" + ex.getMessage(), ex);
            }
        }
        return result;

    }



    /**
     * 根据key直接查到所有的key对应的value值
     * Description: <br>
     *
     * @param key
     * @return Set<String><br>
     * @author yangyang<br>
     * 2019年11月11日
     */
    public List<String> getAllHashValue(String key) {

        List<String> result = new ArrayList<>();
        try {
            result = jedisClusterA.hvals(key);
        } catch (Exception e) {
            logger.error("redis主节点失败，" + e.getMessage(), e);
            try{
                result = jedisClusterB.hvals(key);
            }catch (Exception ex){
                logger.error("redis从节点失败，" + ex.getMessage(), ex);
            }
        }
        return result;
    }

    /**
     * Description:  设置key的有效时间，返回1表示设置成功，返回0表示失败<br>
     *
     * @param key     key
     * @param seconds seconds
     * @return <br>
     * @author zhangai<br>
     * @taskId <br>
     */
    public Long expire(final String key, final int seconds) {
        long result = 0L;
        try {
            result = jedisClusterA.expire(key, seconds);
        } catch (Exception e) {
            logger.error("redis主节点失败，" + e.getMessage(), e);
        }

        try {
            result = jedisClusterB.expire(key, seconds);
        } catch (Exception e) {
            logger.error("redis从节点失败，" + e.getMessage(), e);
        }
        return result;
    }

    /**
     * Description:判断key是否存在 <br>
     *
     * @param key key
     * @return <br>
     * @author zhangai<br>
     * @taskId <br>
     */
    public Boolean exists(final String key) {

        boolean result = false;
        try {
            result = jedisClusterA.exists(key);
        } catch (Exception e) {
            logger.error("redis主节点失败，" + e.getMessage(), e);
            try {
                result = jedisClusterB.exists(key);
            } catch (Exception ex) {
                logger.error("redis从节点失败，" + ex.getMessage(), ex);
            }
        }
        return result;
    }

    /**
     * Description:自增操作 <br>
     *
     * @param key key
     * @return <br>
     * @author zhangai<br>
     * @taskId <br>
     */
    public long incr(final String key) {

        Long result = null;
        try {
            result = jedisClusterA.incr(key);
        } catch (Exception e) {
            logger.error("redis主节点失败，" + e.getMessage(), e);
        }
        try {
            result = jedisClusterB.incr(key);
        } catch (Exception e) {
            logger.error("redis从节点失败，" + e.getMessage(), e);
        }
        return result;
    }

    /**
     * Description:刪除 <br>
     *
     * @param key <br>
     * @author zhpp<br>
     * @taskId <br>
     */
    public void del(String key) {
        try {
            jedisClusterA.del(key);
        } catch (Exception e) {
            logger.error("redis主节点失败，" + e.getMessage(), e);
        }
        try {
            jedisClusterB.del(key);
        } catch (Exception e) {
            logger.error("redis从节点失败，" + e.getMessage(), e);
        }
    }


    /**
     * Description: set并expire操作<br>
     *
     * @param key
     * @param seconds
     * @param value
     * @return String<br>
     * @author yangyang<br>
     * 2017年11月23日
     */
    public String setEx(String key, int seconds, String value) {
        String result = "";
        try {
            result = jedisClusterA.setex(key, seconds, value);
        } catch (Exception e) {
            logger.error("redis主节点失败，" + e.getMessage(), e);
        }

        try {
            result = jedisClusterB.setex(key, seconds, value);
        } catch (Exception e) {
            logger.error("redis从节点失败，" + e.getMessage(), e);
        }

        return result;
    }


    public String set(String key, String value, String nxxx, String expx, long time) {
        String result = "";
        try {
            result = jedisClusterA.set(key, value, nxxx, expx, time);
        } catch (Exception e) {
            logger.error("redis主节点失败，" + e.getMessage(), e);
        }

        try {
            result = jedisClusterB.set(key, value, nxxx, expx, time);
        } catch (Exception e) {
            logger.error("redis从节点失败，" + e.getMessage(), e);
        }

        return result;
    }

    public Map<String, JedisPool> getNodeMap() {
        Map<String, JedisPool> result = new HashMap<>();
        try {
            result = jedisClusterA.getClusterNodes();
        } catch (Exception e) {
            logger.error("redis主节点失败，" + e.getMessage(), e);
        }
        if (result.size() == 0) {
            try {
                result = jedisClusterB.getClusterNodes();
            } catch (Exception e) {
                logger.error("redis从节点失败，" + e.getMessage(), e);
            }
        }
        return result;
    }

    public Map<String, JedisPool> getNodeMapA() {
        return jedisClusterA.getClusterNodes();
    }

    public Map<String, JedisPool> getNodeMapB() {
        return jedisClusterB.getClusterNodes();
    }

    public void delRedisKeys(String matchKey) {
        Jedis jedis = null;
        try {
            Map<String, JedisPool> clusterNodes = jedisClusterA.getClusterNodes();
            for (Map.Entry<String, JedisPool> entry : clusterNodes.entrySet()) {
                logger.info("获取getResource");
                jedis = entry.getValue().getResource();
                logger.info("jedis.info=" + jedis.info("replication"));
                //判断非从节点(因为若主从复制，从节点会跟随主节点的变化而变化)
                if (!jedis.info("replication").contains("role:slave")) {
                    logger.info("执行getScan");
                    getScan(jedis, matchKey);
                }
            }
        } catch (Exception ex) {
            logger.error("delRedisKeys" + ex.getMessage(), ex);
        } finally {
            if (null != jedis) {
                jedis.close();
            }
        }

        try {
            Map<String, JedisPool> clusterNodes = jedisClusterB.getClusterNodes();
            for (Map.Entry<String, JedisPool> entry : clusterNodes.entrySet()) {
                logger.info("获取getResource");
                jedis = entry.getValue().getResource();
                logger.info("jedis.info=" + jedis.info("replication"));
                //判断非从节点(因为若主从复制，从节点会跟随主节点的变化而变化)
                if (!jedis.info("replication").contains("role:slave")) {
                    logger.info("执行getScan");
                    getScan(jedis, matchKey);
                }
            }
        } catch (Exception ex) {
            logger.error("delRedisKeys" + ex.getMessage(), ex);
        }finally {
            if (null != jedis) {
                jedis.close();
            }
        }
    }

    public void getScan(Jedis redisService, String key) {
        try {
            ScanParams params = new ScanParams();
            params.match(key);
            params.count(50000);
            String cursor = "0";
            logger.info("执行数据50000");
            Pipeline pl = redisService.pipelined();
            while (true) {
                ScanResult<String> scanResult = redisService.scan(cursor, params);
                List<String> elements = scanResult.getResult();
                if (elements != null && !elements.isEmpty()) {
                    for (String temp : elements) {
                        pl.del(temp);
                    }
                    pl.sync();
                    Thread.sleep(50L);
                    logger.info("删除数据50000");
                }
                cursor = scanResult.getStringCursor();
                if ("0".equals(cursor)) {
                    break;
                }
            }
        }catch(InterruptedException ex2){
            Thread.currentThread().interrupt();
            logger.error("getScanException:{}" , ex2.getMessage());
        }catch (Exception ex) {
            logger.error("getScanException:{}" , ex.getMessage());
        }
    }

}
